<?php

namespace app\service\ai;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use hunma\exception\ApiException;
use support\Log;

/**
 * DeepseekClient - 用于与 DeepSeek AI API 交互的客户端
 */
class DeepseekClient
{
    /**
     * @var string API 端点 URL
     */
    protected string $apiUrl;

    /**
     * @var string 用于身份验证的 API 密钥
     */
    protected string $apiKey;

    /**
     * @var string 用于完成任务的模型
     */
    protected string $model;

    /**
     * @var array 对话历史
     */
    protected array $messages = [];

    /**
     * @var array 默认请求参数
     */
    protected array $defaultParams = [
        'temperature' => 1,
        'max_tokens' => 2048,
        'top_p' => 1,
        'frequency_penalty' => 0,
        'presence_penalty' => 0,
        'stream' => false
    ];

    /**
     * @var Client Guzzle HTTP 客户端
     */
    protected Client $client;

    /**
     * 构造函数
     *
     * @param string $apiKey DeepSeek API 密钥
     * @param array $options 附加配置选项
     */
    public function __construct(array $options = [])
    {

        $this->apiKey = getenv('DEEPSEEK_API_KEY');
        $this->apiUrl = getenv('DEEPSEEK_API_URL', 'https://api.deepseek.com/chat/completions');
        $this->model = getenv('DEEPSEEK_API_MODEL', 'deepseek-chat');

        // 初始化 Guzzle 客户端
        $this->client = new Client(['verify'=>false,'timeout' => 3000]);

        // 覆盖模型参数（如果提供）
        if (!empty($options['model'])) {
            $this->model = $options['model'];
        }

        // response_format如果空就默认值
        if (isset($options['response_format']) && is_array($options['response_format'])) {
            $this->defaultParams['response_format'] = $options['response_format'];
        } else{
            $this->defaultParams['response_format'] = ['type' => 'json_object'];
        }

        // 覆盖其他默认参数（如果提供）
        foreach (['temperature', 'max_tokens', 'top_p', 'frequency_penalty', 'presence_penalty'] as $param) {
            if (isset($options[$param])) {
                $this->defaultParams[$param] = $options[$param];
            }
        }

    }

    /**
     * 设置系统消息
     *
     * @param string $content 系统消息内容
     * @return $this
     */
    public function setSystemMessage(string $content): self
    {
        // 删除任何现有的系统消息
        $this->messages = array_filter($this->messages, function($message) {
            return $message['role'] !== 'system';
        });

        // 在开头添加新的系统消息
        array_unshift($this->messages, [
            'role' => 'system',
            'content' => $content
        ]);

        return $this;
    }

    /**
     * 向对话添加用户消息
     *
     * @param string $content 用户消息内容
     * @return $this
     */
    public function addUserMessage(string $content): self
    {
        $this->messages[] = [
            'role' => 'user',
            'content' => $content
        ];

        return $this;
    }

    /**
     * 向对话添加助手消息
     *
     * @param string $content 助手消息内容
     * @return $this
     */
    public function addAssistantMessage(string $content): self
    {
        $this->messages[] = [
            'role' => 'assistant',
            'content' => $content
        ];

        return $this;
    }

    /**
     * 清除所有对话历史
     *
     * @return $this
     */
    public function clearConversation(): self
    {
        $this->messages = [];
        return $this;
    }

    /**
     * 获取当前对话历史
     *
     * @return array
     */
    public function getMessages(): array
    {
        return $this->messages;
    }

    /**
     * 向 DeepSeek API 发送完成请求
     *
     * @param array $options 覆盖默认值的附加请求选项
     * @return array 来自 API 的解析响应
     * @throws ApiException
     */
    public function sendRequest(array $options = []): array
    {
        if (empty($this->messages)) {
            throw new ApiException('对话中没有提供消息', 400);
        }

        // 合并默认参数与提供的选项
        $requestParams = array_merge($this->defaultParams, $options);
        $requestParams['model'] = $this->model;
        $requestParams['messages'] = $this->messages;
        $requestParams['response_format'] = ['type' => 'text'];

        $headers = [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'Authorization' => "Bearer {$this->apiKey}"
        ];

        try {
            $request = new Request(
                'POST',
                $this->apiUrl,
                $headers,
                json_encode($requestParams)
            );

            $response = $this->client->sendAsync($request)->wait();
            $responseBody = $response->getBody()->getContents();
            $result = json_decode($responseBody, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new ApiException('无法解析 API 响应: ' . json_last_error_msg(), 500);
            }

            // 检查响应是否包含预期的结构
            if (!isset($result['choices'][0]['message'])) {
                throw new ApiException('API 响应格式异常', 500);
            }

            // 将助手的响应添加到对话历史中
            $assistantMessage = $result['choices'][0]['message']['content'];
            $this->addAssistantMessage($assistantMessage);

            return $result;
        } catch (GuzzleException $e) {
            Log::error('DeepSeek API 请求失败', [
                'error' => $e->getMessage(),
                'code' => $e->getCode(),
                'trace' => $e->getTraceAsString()
            ]);
            throw new ApiException('与 DeepSeek API 通信失败: ' . $e->getMessage(), 500);
        } catch (\Exception $e) {
            Log::error('DeepSeek API 错误', [
                'error' => $e->getMessage(),
                'code' => $e->getCode(),
                'trace' => $e->getTraceAsString()
            ]);
            throw new ApiException('处理 DeepSeek API 请求时出错: ' . $e->getMessage(), 500);
        }
    }

    /**
     * 发送包含单个用户消息的完成请求
     *
     * @param string $message 用户消息
     * @param array $options 附加请求选项
     * @return string 助手的响应
     * @throws ApiException
     */
    public function chat(string $message, array $options = []): string
    {
        $this->addUserMessage($message);
        $response = $this->sendRequest($options);
        return $response['choices'][0]['message']['content'];
    }

    /**
     * 从最新的 API 调用中仅获取助手的响应内容的辅助方法
     *
     * @param array $response 完整的 API 响应
     * @return string 助手的消息内容
     */
    public function getResponseContent(array $response): string
    {
        return $response['choices'][0]['message']['content'] ?? '';
    }

    /**
     * 获取令牌使用信息的辅助方法
     *
     * @param array $response 完整的 API 响应
     * @return array 令牌使用统计
     */
    public function getTokenUsage(array $response): array
    {
        return $response['usage'] ?? [];
    }

    /**
     * 配置流式模式
     *
     * @param bool $enabled 是否启用流式处理
     * @param array $streamOptions 流特定选项
     * @return $this
     */
    public function setStreaming(bool $enabled, array $streamOptions = null): self
    {
        $this->defaultParams['stream'] = $enabled;
        if ($streamOptions !== null) {
            $this->defaultParams['stream_options'] = $streamOptions;
        }
        return $this;
    }
}